home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Technotools
/
Technotools (Chestnut CD-ROM)(1993).ISO
/
lang_c
/
cug189
/
roff.c
< prev
next >
Wrap
Text File
|
1985-08-21
|
11KB
|
535 lines
/* text formatter transcribed from the book Software Tools */
#include <ctype.h>
#include <stdio.h>
#define PAGEWIDTH 60 /* default page width */
#define PAGELEN 66 /* default page length */
#define MAXLINE 255
#define PAGECHAR '#' /* page number escape char */
#define HUGE 32700
#define YES 1
#define NO 0
#define OK 1
#define max(a,b) (a >= b) ? a : b
#define min(a,b) (a <= b) ? a : b
#define abs(x) (x >= 0) ? x : -x
int fill = YES, /* in fill mode if YES */
lsval = 1, /* current line spacing */
inval = 0, /* current indent; >= 0 */
rmval = PAGEWIDTH, /* current right margin */
tival = 0, /* current temporary indent */
ceval = 0, /* number of lines to center */
ulval = 0, /* number of lines to underline */
curpag = 0, /* current output page number */
newpag = 1, /* next output page number */
lineno = 0, /* next line to be printed */
plval = PAGELEN, /* page length in lines */
m1val = 2, /* top margin, including header */
m2val = 3, /* margin after header */
m3val = 2, /* margin after last text line */
m4val = 3, /* bottom margin, including footer */
bottom, /* last live line on page: */
/* = plval - m3val - m4val */
outp, /* index into outbuf */
outw, /* width of text in outbuf */
outwds, /* number of words in outbuf */
dir; /* directions flag */
char header[MAXLINE], /* top of page title */
footer[MAXLINE], /* bottom of page title */
outbuf[MAXLINE]; /* lines to be filled go here */
main(argc,argv)
int argc;
char *argv[];
{
register i;
init();
for (i = 1; i < argc; ++i)
if (freopen(argv[i],"r",stdin) == NULL)
fprintf(stderr,"can't open %s\n",argv[i]);
else
roff();
}
/* initialize header, footer, and line-count invariant */
init()
{
bottom = plval - m3val - m4val; /* invariant */
strcpy(header,"\n");
strcpy(footer,"\n");
}
/* format current file */
roff()
{
char inbuf[MAXLINE];
while (fgets(inbuf,MAXLINE-1,stdin) != NULL)
if (inbuf[0] == '.')
command(inbuf);
else
text(inbuf);
if (lineno > 0)
space(HUGE);
}
/* perform formatting command */
command(buf)
char *buf;
{
int val, spval;
char *argtyp;
val = getval(buf,argtyp);
if (lookup(buf,"bp"))
{
if (lineno > 0)
space(HUGE);
set(&curpag,val,argtyp,curpag+1,-HUGE,HUGE);
newpag = curpag;
}
else if (lookup(buf,"br"))
brk();
else if (lookup(buf,"ce"))
{
brk();
set(&ceval,val,argtyp,1,0,HUGE);
}
else if (lookup(buf,"fi"))
{
brk();
fill = YES;
}
else if (lookup(buf,"fo"))
strcpy(footer,buf+3);
else if (lookup(buf,"he"))
strcpy(header,buf+3);
else if (lookup(buf,"in"))
{
set(&inval,val,argtyp,0,0,rmval-1);
tival = inval;
}
else if (lookup(buf,"ls"))
set(&lsval,val,argtyp,1,1,HUGE);
else if (lookup(buf,"nf"))
{
brk();
fill = NO;
}
else if (lookup(buf,"pl"))
{
set(&plval,val,argtyp,PAGELEN,m1val+m2val+m3val+m4val+1,HUGE);
bottom=plval-m3val-m4val;
}
else if (lookup(buf,"rm"))
set(&rmval,val,argtyp,PAGEWIDTH,tival+1,HUGE);
else if (lookup(buf,"sp"))
{
set(&spval,val,argtyp,1,0,HUGE);
space(spval);
}
else if (lookup(buf,"ti"))
{
brk();
set(&tival,val,argtyp,0,0,rmval);
}
else if (lookup(buf,"ul"))
set(&ulval,val,argtyp,0,1,HUGE);
else
return; /* ignore unknown commands */
}
/* lookup routine for commands */
lookup(buf,string)
char *buf, *string;
{
return (buf[1] == string[0]) && (buf[2] == string[1]);
}
/* evaluate optional numeric argument */
getval(buf,argtyp)
char *buf, *argtyp;
{
int i;
i = 3;
/* ..find argument.. */
while (buf[i] == ' ' || buf[i] == '\t')
++i;
*argtyp = buf[i];
if (*argtyp == '+' || *argtyp=='-')
i++;
return(atoi(buf+i));
}
/* set parameter and check range */
set(param,val,argtyp,defval,minval,maxval)
int *param,val,defval,minval,maxval;
char *argtyp;
{
if (*argtyp == '\n')
*param = defval;
else if (*argtyp == '+')
*param += val;
else if (*argtyp == '-')
*param -= val;
else
*param = val;
*param = min(*param,maxval);
*param = max(*param,minval);
}
/* process text lines */
text(inbuf)
char *inbuf;
{
char wrdbuf[MAXLINE];
int i;
if (isspace(*inbuf))
leadbl(inbuf); /* go left. set tival */
if (ulval > 0)
{
underl(inbuf,wrdbuf,MAXLINE);
ulval--;
}
if (ceval > 0)
{
center(inbuf);
put(inbuf);
ceval--;
}
else if (*inbuf == '\n')
put(inbuf);
else if (fill == NO)
put(inbuf);
else
{
i = 0;
while (getwrd(inbuf,&i,wrdbuf) > 0)
putwrd(wrdbuf);
}
}
/* delete leading blanks. Set tival */
leadbl(buf)
char *buf;
{
register i,j;
brk();
/* find first non blank */
i = 0;
while (buf[i] == ' ')
i++;
if (buf[i] != '\n')
tival += i;
/* move line to left */
j = 0;
while ((buf[j++] = buf[i++]) != '\0') ;
}
/* put out line with proper spacing and indenting */
put(buf)
char *buf;
{
register i;
if ((lineno == 0) || (lineno > bottom))
phead();
i = 1;
while (i++ <= tival)
putchar(' ');
tival = inval; /* tival good for one line only */
fputs(buf,stdout);
skip(min(lsval-1,bottom-lineno));
lineno += lsval;
if (lineno > bottom)
pfoot();
}
/* put out page header */
phead()
{
curpag = newpag++;
if (m1val > 0)
{
skip(m1val-1);
puttl(header,curpag);
}
skip(m2val);
lineno = m1val+m2val+1;
}
/* put out page footer */
pfoot()
{
skip(m3val);
if (m4val > 0)
{
puttl(footer,curpag);
skip(m4val-1);
}
}
/* put out title line with optional page number */
puttl(buf,pageno)
char *buf;
int pageno;
{
register i;
for (i = 0; buf[i] != '\n' && buf[i] != '\0'; i++)
if (buf[i] == PAGECHAR)
printf("%*d",1,pageno);
else
putchar(buf[i]);
putchar('\n');
}
/* space n lines or to bottom of page */
space(n)
int n;
{
brk();
if (lineno > bottom)
return;
if (lineno == 0)
phead();
skip(min(n,bottom+1-lineno));
lineno += n;
if (lineno > bottom)
pfoot();
}
/* output n blank lines */
skip(n)
register n;
{
while ((n--) > 0)
putchar('\n');
}
/* get non-blank word from in[i] into out.
* increment *i.
*/
getwrd(in,ii,out)
char *in, *out;
int *ii;
{
register i, j;
i = *ii;
while ((in[i] == ' ') || (in[i] == '\t'))
i++;
j = 0;
while ( (in[i] != '\0') && !isspace(in[i]) )
out[j++] = in[i++];
out[j] = '\0';
*ii = i; /* return index in ii */
return(j); /* return length of word */
}
/* put a word in outbuf; includes margin justification */
putwrd(wrdbuf)
char *wrdbuf;
{
int last, llval, w, nextra;
w = width(wrdbuf);
/* new end of wrdbuf */
last = strlen(wrdbuf)+outp+1;
llval = rmval-tival;
if ( (outp > 0) && ((outw+w>llval) || (last>=MAXLINE)) )
{
/* too big */
last -= outp; /* remember end of wrdbuf */
nextra = llval-outw+1;
spread(outbuf,outp-1,nextra,outwds);
if (nextra > 0 && outwds > 1)
outp += nextra;
brk(); /* flush previous line */
}
strcpy(outbuf+outp,wrdbuf);
outp = last;
outbuf[outp-1] = ' '; /* blank between words */
outw += w+1; /* 1 extra for blank */
outwds++;
}
/* spread words to justify right margin */
spread(buf,outp,ne,outwds)
char *buf;
int outp, ne, outwds;
{
register nholes, i, j, nb;
if (ne <= 0 || outwds <= 1)
return;
dir = 1-dir; /* reverse direction */
nholes = outwds-1;
i = outp-1;
/* leave room for NEWLINE, EOS */
j = min(MAXLINE-2,i+ne);
while (i < j)
{
buf[j] = buf[i];
if (buf[i] == ' ')
{
/* compute # of blanks */
if (dir == 0)
nb = (ne-1)/nholes+1;
else
nb = ne/nholes;
ne -= nb;
nholes--;
/* put blanks in buffer */
while (nb-- > 0)
buf[--j] = ' ';
}
i--;
j--;
}
}
/* compute width of character string */
width(buf)
char *buf;
{
register i, val;
for (val = i = 0; buf[i] != '\0'; i++)
if (buf[i] == '\b')
val--;
else if (buf[i] != '\n')
val++;
return(val);
}
/* end current filled line */
brk()
{
if (outp > 0)
{
outbuf[outp-1] = '\n';
outbuf[outp] = '\0';
put(outbuf);
}
outp = outw = outwds = 0;
}
/* center a line by setting tival */
center(buf)
char *buf;
{
tival = max((rmval+tival-width(buf))/2,0);
}
/* underline a line */
underl(buf,tbuf,size)
char *buf, *tbuf;
int size;
{
int i, j,
k, k1; /* how many chars in last word */
i = j = k = 0;
while (j < size-2)
{
if (isspace(buf[i]))
{
k1 = k;
while (k-- > 0)
{
if (j >= size-2)
break;
tbuf[j++] = '\b';
}
k = k1;
while (k-- > 0) {
if (j >= size-2)
break;
tbuf[j++] = '_';
}
}
if (buf[i] == '\n')
break;
else if (j >= size-2)
break;
else
{
if (buf[i] != ' ' && buf[i] != '\t')
k++;
else
k = 0;
tbuf[j++] = buf[i++];
}
}
tbuf[j++] = '\n';
tbuf[j] = '\0';
strcpy(buf,tbuf);
}
while (k-- > 0) {
if (j >= size-2)